﻿using EmbeddedSharp.Core;
using EmbeddedSharp.Scripting.Function;

namespace EmbeddedSharp.Scripting
{
    /// <summary>
    /// Context function manager
    /// </summary>
    public class ContextFunctionManager : DefaultFunctionManager
    {
        /// <summary>
        /// Default constructor
        /// </summary>
        public ContextFunctionManager()
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        public ContextFunctionManager(IContext context)
        {
            Context = context;
        }

        /// <summary>
        /// The context
        /// </summary>
        public IContext Context { get; set; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="funcName"></param>
        /// <param name="func"></param>
        public override void Add(string funcName, object func)
        {
            if (func is ContextFuncNode)
            {
                var cfn = func as ContextFuncNode;
                cfn.Context = Context;
            }

            base.Add(funcName, func);
        }

        /// <summary>
        /// Get the function node
        /// </summary>
        /// <param name="functionName"></param>
        /// <returns></returns>
        public override FuncNode GetFunction(string functionName)
        {
            FuncNode fn = base.GetFunction(functionName);

            if (fn is UserDefinedFunctionNode)
            {
                var udf = fn as UserDefinedFunctionNode;
                var newUdf
                    = new UserDefinedFunctionNode
                          {
                              Name = udf.Name,
                              FuncBody = udf.FuncBody,
                              Comment = udf.Comment,
                              FunctionManager = udf.FunctionManager,
                              Arguments = new string[udf.Arguments.Length],
                              ClassName = udf.ClassName,
                              LineNumber = udf.LineNumber,
                              Value = udf.Value,
                              ParserFactory = udf.ParserFactory,
                              Context = Context
                          };
                for (int index = 0;
                     index < udf.Arguments.Length;
                     index++)
                {
                    newUdf.Arguments[index] = udf.Arguments[index];
                }

                return newUdf;
            }
            if (fn != null && fn is ContextFuncNode)
            {
                ((ContextFuncNode) fn).Context = Context;
            }

            return fn;
        }


        /// <summary>
        /// Check if the function is defined by user.
        /// </summary>
        /// <param name="funcName">the function name</param>
        /// <returns>true if the function is user defined</returns>
        public override bool IsUserDefinedFunction(string funcName) {
            if (!Functions.ContainsKey(funcName)) {
                return false;
            }

            FuncNode function = Functions[funcName] as FuncNode;
            if (function != null) {
                return function is UserDefinedFunctionNode;
            }

            return false;
        }
    }
}